package disjunction.examples.entities
{
	import disjunction.core.*;
	import disjunction.core.geom.Vector2;
	import disjunction.extensions.math.MathUtils;
	import disjunction.extensions.view.DisplayObjectEntityListView;
	
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	
	/**
	 * Entities Example controller.
	 * 
	 * @author Nick Wiggill
	 */
	
	public class DemoController extends EntityListController
	{
		public override function initialise(data:Object):void
		{
			trace('custom controller init');
			
			
			//initialiseModel(data);
			//initialiseView();
			//start();
			
			//0. Prepare self.
			timer.baseUpdateIntervalMs = 20; //50 fps
			timer.updateTimeoutMs = 500;
			
			//1. Prepare model.
			model = new DemoModel();
			model.worldDimensions = data.viewDimensions;

			var entity:DemoEntityModel;
			var numEntities:Number = 
				Math.random() * (model.MAX_ENTITIES - model.MIN_ENTITIES) + model.MIN_ENTITIES;
			
			for (var i:int = 0; i < numEntities; i++)
			{
				entity = new DemoEntityModel();
				entity.radius = Math.random() * 5 + 5;
				entity.position = new Vector2(
					Math.random() * model.worldDimensions.x,
					Math.random() * model.worldDimensions.y
				);
				entity.motion = new Vector2(
					Math.random() * 200 - 100, 
					Math.random() * 200 - 100
				);
				entity.type = int(Math.random() * 4); //num types!

				//will create and push a new view according to CreationStrategy's
				//treatment of the given entity model.
				//entities.add(entity);
				addEntity(entity);
			}
			
			//2. Prepare view.
			//var view:DisplayObjectEntityListView = new DisplayObjectEntityListView();
			var view:DemoView = new DemoView();
			//view.model = model; //must be done before initialisation
			view.context = data.viewContext;
			//view.initialise(data.viewContext);
			views["main"] = view;
			
			//3. Run controller updates.
			timer.start();
		}
		
		public override function update(timeDeltaMs:uint):void
		{
			trace('custom controller update');
			var rotation:Number;

			for each (var entity:DemoEntityModel in model.current)
			{
				switch (entity.type)
				{
					case DemoEntityModel.TYPE_BOUNCER:
						//apply motion in pixels per second
						entity.position.addLocal(entity.motion.mul(timeDeltaMs/1000));
						
						//bounce if edge hit
						
						if (entity.position.x < entity.radius ||
							entity.position.x > model.worldDimensions.x - entity.radius)
							entity.motion.x *= -1;
						
						if (entity.position.y < entity.radius ||
							entity.position.y > model.worldDimensions.y - entity.radius)
							entity.motion.y *= -1;
						break;
					
					case DemoEntityModel.TYPE_DANCER:
						//rotate motion vector by some random value
						entity.motion.rotateLocal(Math.random()*Math.PI/18 - Math.PI/9);
						//apply motion in pixels per second
						entity.position.addLocal(entity.motion.mul(timeDeltaMs/1000));
						break;
					
					case DemoEntityModel.TYPE_WANDERER:
						//rotate motion vector by some random value
						rotation = (Math.random() * .6) - .3;
						entity.motion.rotateLocal(rotation);
						//apply motion in pixels per second
						entity.position.addLocal(entity.motion.mul(timeDeltaMs/1000));
						//keep in bounds
						entity.position.x = MathUtils.clamp(entity.position.x, 0, model.worldDimensions.x);
						entity.position.y = MathUtils.clamp(entity.position.y, 0, model.worldDimensions.y);
						break;
					
					case DemoEntityModel.TYPE_JITTERER:
						//rotate motion vector by some random value
						rotation = (Math.random() * 20) - 10;
						entity.motion.rotateLocal(rotation);
						//apply motion in pixels per second
						entity.position.addLocal(entity.motion.mul(timeDeltaMs/1000));
						//keep in bounds
						entity.position = new Vector2(
							MathUtils.clamp(entity.position.x, 0, model.worldDimensions.x),
							MathUtils.clamp(entity.position.y, 0, model.worldDimensions.y)
						);
						break;
				}
				
			}
			
			super.update(timeDeltaMs);
			
			(views["main"] as IView).update(timeDeltaMs);
		}
		/*
		public function get model():DemoModel
		{
			return model_ as DemoModel;
		}
		*/
	}
}